package pwaf.client;

import java.util.ArrayList;
import java.util.List;

import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.core.client.GWT;
import com.google.gwt.dom.client.Style.Unit;
import com.google.gwt.user.client.Window.Location;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.DecoratedPopupPanel;
import com.google.gwt.user.client.ui.DockLayoutPanel;
import com.google.gwt.user.client.ui.HasVerticalAlignment;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.Image;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.PopupPanel.PositionCallback;
import com.google.gwt.user.client.ui.RootLayoutPanel;
import com.google.gwt.user.client.ui.SimplePanel;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.google.maps.gwt.client.GoogleMap;
import com.google.maps.gwt.client.LatLng;
import com.google.maps.gwt.client.MapOptions;
import com.google.maps.gwt.client.MapTypeId;
import com.google.maps.gwt.client.Marker;
import com.google.maps.gwt.client.Marker.ClickHandler;
import com.google.maps.gwt.client.Marker.MouseOutHandler;
import com.google.maps.gwt.client.Marker.MouseOverHandler;
import com.google.maps.gwt.client.MarkerOptions;
import com.google.maps.gwt.client.MouseEvent;
import com.google.maps.gwt.client.Point;

public class Frontpage implements EntryPoint {

	private static final boolean THUMBNAIL_NEAR_POINTER = true;
	private static final int THUMBNAIL_PADDING = 20;

	private SimplePanel mapPanel;
	private GoogleMap map;

	private Label messageLabel;

	private DecoratedPopupPanel popup;
	private Label popupLabel;
	private Image popupImage;

	@Override
	public void onModuleLoad() {
		HorizontalPanel titlePanel = new HorizontalPanel();
		titlePanel.setVerticalAlignment(HasVerticalAlignment.ALIGN_MIDDLE);
		titlePanel.addStyleName("titlePanel");
		Label titleLabel = new Label("Picasa Web Albums Frontpage");
		titleLabel.addStyleName("titleLabel");
		titlePanel.add(titleLabel);

		mapPanel = new SimplePanel();
		mapPanel.addStyleName("mapPanel");

		HorizontalPanel messagePanel = new HorizontalPanel();
		messagePanel.setVerticalAlignment(HasVerticalAlignment.ALIGN_MIDDLE);
		messagePanel.addStyleName("messagePanel");
		messageLabel = new Label();
		messageLabel.addStyleName("messageLabel");
		messagePanel.add(messageLabel);

		DockLayoutPanel layout = new DockLayoutPanel(Unit.PCT);
		layout.addNorth(titlePanel, 4);
		layout.addSouth(messagePanel, 4);
		layout.add(mapPanel);
		RootLayoutPanel.get().add(layout);

		popup = new DecoratedPopupPanel();
		popup.addStyleName("popup");
		VerticalPanel popupPanel = new VerticalPanel();
		HorizontalPanel popupLabelPanel = new HorizontalPanel();
		popupLabelPanel.setVerticalAlignment(HasVerticalAlignment.ALIGN_MIDDLE);
		popupLabel = new Label();
		popupLabel.addStyleName("popupLabel");
		popupLabelPanel.add(popupLabel);
		popupPanel.add(popupLabelPanel);
		popupImage = new Image();
		popupLabel.addStyleName("popupImage");
		popupPanel.add(popupImage);
		popup.setWidget(popupPanel);

		loadMap();
		loadAlbums();
	}

	private void loadMap() {
		MapOptions mapOptions = MapOptions.create();
		mapOptions.setMapTypeId(MapTypeId.ROADMAP);
		mapOptions.setZoom(3);
		map = GoogleMap.create(mapPanel.getElement(), mapOptions);
		map.setCenter(LatLng.create(0, 0));
	}

	private void loadAlbums() {
		final String user = Location.getParameter("user");
		AlbumsServiceAsync albumsService = GWT.create(AlbumsService.class);
		albumsService.getAlbums(user, new AsyncCallback<List<Album>>() {

			@Override
			public void onSuccess(List<Album> albums) {
				// TODO center map on mapped albums
				// TODO handle maps with same location

				List<Album> unmapped = new ArrayList<Album>();
				for (final Album album : albums) {
					if (album.hasLatLng) {
						final LatLng coords = LatLng.create(album.lat, album.lng);

						MarkerOptions markerOptions = MarkerOptions.create();
						markerOptions.setPosition(coords);
						Marker marker = Marker.create(markerOptions);
						marker.addMouseOverListener(new MouseOverHandler() {

							@Override
							public void handle(MouseEvent event) {
								popupLabel.setText(album.title);
								popupImage.setUrl(album.thumbnail);

								// TODO handle coordinates when map tiling (due to zooming out a lot)
								popup.setPopupPositionAndShow(new PositionCallback() {

									@Override
									public void setPosition(int offsetWidth, int offsetHeight) {
										if (THUMBNAIL_NEAR_POINTER) {
											double scale = Math.pow(2, map.getZoom());
											double mapLat = map.getBounds().getNorthEast().lat();
											double mapLng = map.getBounds().getSouthWest().lng();
											Point mapPos = map.getProjection().fromLatLngToPoint(
													LatLng.create(mapLat, mapLng));
											Point markerPos = map.getProjection().fromLatLngToPoint(coords);

											int x = (int) Math.floor((markerPos.getX() - mapPos.getX()) * scale);
											int y = (int) Math.floor((markerPos.getY() - mapPos.getY()) * scale);
											popup.setPopupPosition(mapPanel.getAbsoluteLeft() + x - (offsetWidth / 2),
													mapPanel.getAbsoluteTop() + y);
										} else {
											int x = mapPanel.getAbsoluteLeft() + THUMBNAIL_PADDING;
											int y = mapPanel.getAbsoluteTop() + mapPanel.getOffsetHeight()
													- THUMBNAIL_PADDING;
											popup.setPopupPosition(x, y - offsetHeight);
										}
									}
								});
							}
						});
						marker.addMouseOutListener(new MouseOutHandler() {

							@Override
							public void handle(MouseEvent event) {
								popup.hide();
							}
						});
						marker.addClickListener(new ClickHandler() {

							@Override
							public void handle(MouseEvent event) {
								Location.assign("http://picasaweb.google.com/" + album.path);
							}
						});
						marker.setMap(map);
					} else {
						unmapped.add(album);
					}
				}

				String message = "Total albums: " + albums.size();
				if (!unmapped.isEmpty()) {
					message += " / Unmapped albums: " + unmapped.size() + " -->";
					for (Album album : unmapped) {
						message += " " + album.title;
					}
				}
				messageLabel.setText(message);
			}

			@Override
			public void onFailure(Throwable error) {
				messageLabel.setText(error.getMessage());
			}
		});
	}
}
